﻿// Copyright (c) Microsoft Corporation.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Data;
using System.Data.EntityClient;

namespace EdmMetadataHelpers
{
    /// <summary>
    /// A simple class that allows you to Materialize an EntityDataReader as XML
    /// </summary>
    public static class EdmXmlAdapter
    {
        /// <summary>
        /// Materializes an Enumeration of XElement(s) from an EntityDataReader
        /// </summary>
        public static IEnumerable<XElement> GetElements(EntityDataReader reader)
        {
            return GetElements((IDataReader) reader);
        }
        /// <summary>
        /// Materialize an Enumeration of XElement(s) from an IDataReader
        /// 
        /// <remarks>Can only materialize rows if they implement IExtendedDataRecord</remarks>
        /// </summary>
        private static IEnumerable<XElement> GetElements(IDataReader reader)
        {
            return from r in reader.Enumerate().OfType<IExtendedDataRecord>()
                     select CreateElement(r);         
        }
        /// <summary>
        /// Materialize an Enumeration of XElement(s) from an IExtendedDataRecord
        /// </summary>
        private static IEnumerable<XElement> GetElements(IExtendedDataRecord record)
        {
            return from field in record.DataRecordInfo.FieldMetadata
                   let fieldname = field.FieldType.Name
                   select new XElement(fieldname, GetData(record[fieldname]));
        }
        /// <summary>
        /// Creates a root node for an IExtendedDataRecord.
        /// 
        /// <remarks>
        /// Attempts to give the root node a meaningful name if possible. 
        /// If however the IExtendedDataRecord holds a projection the root node will be called "Row"
        /// </remarks>
        /// </summary>
        private static XElement CreateElement(IExtendedDataRecord record)
        {
            string definition = record.DataRecordInfo.RecordType.EdmType.FullName;
            string name = definition.Contains("[") ? "Row" : definition;
            

            XElement root = new XElement(name);

            if (definition != name) root.Add(new XAttribute("Definition", definition ));
            root.Add(GetElements(record));
            return root;
        }

        /// <summary>
        /// Take the object and save either as the Value of an XElement
        /// or if it is a Row type or a Reader type create a root element
        /// and fill that with the Row(s)
        /// </summary>
        private static Object GetData(Object obj)
        {
            if (obj is IExtendedDataRecord)
            {
                IExtendedDataRecord record = obj as IExtendedDataRecord;
                IDataReader reader = obj as IDataReader;
                if (reader == null)
                {
                    return CreateElement(record);
                }
                else
                {
                    //Create a new Element called "Rows"
                    // and fill that:
                    return new XElement("Rows", GetElements(reader));
                }
            }
            else
            {
                return obj;
            }
        }
    }
}
